package com.jzo2o.customer.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.customer.dto.response.AddressBookResDTO;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.common.expcetions.ServerErrorException;
import com.jzo2o.common.handler.UserInfoHandler;
import com.jzo2o.common.model.CurrentUserInfo;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.*;
import com.jzo2o.customer.enums.AddressDefaultStatusEnum;
import com.jzo2o.customer.mapper.AddressBookMapper;
import com.jzo2o.customer.model.domain.AddressBook;
import com.jzo2o.customer.model.dto.request.AddressBookPageQueryReqDTO;
import com.jzo2o.customer.model.dto.request.AddressBookUpsertReqDTO;
import com.jzo2o.customer.service.IAddressBookService;
import com.jzo2o.mvc.model.Result;
import com.jzo2o.mysql.utils.PageUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 地址薄 服务实现类
 * </p>
 */
@Service
public class AddressBookServiceImpl extends ServiceImpl<AddressBookMapper, AddressBook> implements IAddressBookService {

    /**
     * 用户信息处理器---底层使用了ThreadLocal
     * 构造器注入
     */
    private final UserInfoHandler userInfoHandler;
    public AddressBookServiceImpl(UserInfoHandler userInfoHandler) {
        this.userInfoHandler = userInfoHandler;
    }

    /**
     * 获取当前用户的id
     * 代替 UserContext.currentUserId() 解耦且提高扩展性
     */
    private Long currentUserId() {
        // 1、判断当前用户是存在
        if (ObjectUtils.isEmpty(userInfoHandler)) {
            throw new ServerErrorException("不能获取当前用户信息，获取地址失败");
        } else {
            // 2、获取当前用户信息
            CurrentUserInfo currentUserInfo = userInfoHandler.currentUserInfo();
            // 3、判断当前用户信息是否为空
            if (ObjectUtils.isEmpty(currentUserInfo)) {
                throw new ServerErrorException("不能获取当前用户信息，获取地址失败");
            } else {
                // 4、返回当前用户id
                return currentUserInfo.getId();
            }
        }
    }

    /**
     * 根据用户id和城市编码查询地址薄
     *
     * @param userId 用户id
     * @param city   城市编码
     * @return 地址薄
     */
    @Override
    public List<AddressBookResDTO> getByUserIdAndCity(Long userId, String city) {

        List<AddressBook> addressBooks = lambdaQuery()
                .eq(AddressBook::getUserId, userId)
                .eq(AddressBook::getCity, city)
                .list();
        if (CollUtils.isEmpty(addressBooks)) {
            return new ArrayList<>();
        }
        return BeanUtils.copyToList(addressBooks, AddressBookResDTO.class);
    }


    /**
     * 将新增地址请求DTO转换为数据库实体
     * 用于新增地址与修改地址
     *
     * @param addressBookUpsertReqDTO 前端新增地址请求参数
     * @return 待保存的地址实体
     */
    private AddressBook getAddressBookByUpsertReqDTO(AddressBookUpsertReqDTO addressBookUpsertReqDTO) {
        // 从location字段解析经纬度（格式："经度,纬度"）
        String location = addressBookUpsertReqDTO.getLocation();
        Double lon = null, lat = null;
        // 如果不为空，则以逗号分割后赋值给经纬度变量
        if (!ObjectUtils.isEmpty(location)) {
            String[] pos = location.split(",");
            if (pos.length == 2) {
                lon = Double.parseDouble(pos[0]);
                lat = Double.parseDouble(pos[1]);
            }
        }
        // 构建地址实体：复制DTO属性+绑定当前用户+填充经纬度
        return AddressBook.builder()
                .userId(currentUserId())
                .name(addressBookUpsertReqDTO.getName())
                .phone(addressBookUpsertReqDTO.getPhone())
                .province(addressBookUpsertReqDTO.getProvince())
                .city(addressBookUpsertReqDTO.getCity())
                .county(addressBookUpsertReqDTO.getCounty())
                .address(addressBookUpsertReqDTO.getAddress())
                .isDefault(addressBookUpsertReqDTO.getIsDefault())
                .lon(lon).lat(lat)
                .build();
    }

    /**
     * 新增地址（核心业务入口）
     *
     * @param addressBookUpsertReqDTO 新增地址请求参数
     */
    @Override
    @Transactional // 保证更新+插入操作原子性
    public void insert(AddressBookUpsertReqDTO addressBookUpsertReqDTO) {
        // 若新增地址设为默认，则先取消当前用户其他默认地址（保证唯一默认）
        if (addressBookUpsertReqDTO.getIsDefault() == AddressDefaultStatusEnum.DEFAULT.getStatus()) {
            lambdaUpdate()
                    .eq(AddressBook::getUserId, currentUserId())  // 只找当前用户“你自己”的地址（不影响别人）
                    .eq(AddressBook::getIsDefault, AddressDefaultStatusEnum.DEFAULT.getStatus())  // 找到你之前标记为“默认”的地址
                    .set(AddressBook::getIsDefault, AddressDefaultStatusEnum.NONE_DEFAULT.getStatus())  // 把这些旧默认地址改成“非默认”
                    .update();  // 执行这个修改操作
        }
        // 转换DTO为实体并插入数据库
        baseMapper.insert(getAddressBookByUpsertReqDTO(addressBookUpsertReqDTO));
    }

    /**
     * 分页查询地址
     *
     * @param addressBookPageQueryReqDTO 查询条件
     * @return 分页结果
     */
    @Override
    public PageResult<AddressBook> page(AddressBookPageQueryReqDTO addressBookPageQueryReqDTO) {
        //1、获取当前登录用户的id
        Long userId = currentUserId();

        //2、创建MP的Lambda条件构造器（Lambda风格避免硬编码字段名，更安全）
        // 写法1：直接 new 实例化 LambdaQueryWrapper，分两步（创建 + 加条件）
        // LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>();
        // queryWrapper.eq(AddressBook::getUserId, userId);

        // 写法2：通过 Wrappers 工具类静态方法创建，一步链式完成（创建 + 加条件）
        LambdaQueryWrapper<AddressBook> queryWrapper = Wrappers.<AddressBook>lambdaQuery()
                // 添加筛选条件：从AddressBook中获取地址簿的userId = 当前登录用户ID
                .eq(AddressBook::getUserId, userId);
        // 注：MP会自动在此条件后追加"逻辑删除字段=未删除"的条件（如is_deleted=0），无需手动写
        // 因为：在nacos配置中心的共享配置 shared-mysql.yaml 中配置了逻辑删除字段

        // 3. 将前端传递的分页参数（DTO）解析为MP的Page对象（含页码、页大小、排序规则）
        Page<AddressBook> page = PageUtils.parsePageQuery(addressBookPageQueryReqDTO, AddressBook.class);

        // 4. 调用MP的默认分页查询方法：根据page（分页参数）和queryWrapper（筛选条件）执行SQL
        // 执行后，page对象会自动填充总条数、总页数、当前页数据等信息
        Page<AddressBook> addressBookPage = baseMapper.selectPage(page, queryWrapper);
        // 5. 将MP的Page对象转换为自定义的PageResult（屏蔽框架细节，返回前端需要的标准化字段）
        return new PageResult<>(addressBookPage.getPages(),  // 总页数
                addressBookPage.getTotal(),  // 总条数
                addressBookPage.getRecords());// 当前页数据列表
    }

    /**
     * 修改地址
     *
     * @param id                      地址ID
     * @param addressBookUpsertReqDTO 修改地址请求参数
     */
    @Override
    @Transactional
    public void updateById(Long id, AddressBookUpsertReqDTO addressBookUpsertReqDTO) {
        //1、根据ID查询地址
        AddressBook addressBook = baseMapper.selectById(id);
        //2、判断地址是否存在
        if (ObjectUtils.isEmpty(addressBook)) {
            throw new CommonException("地址id不存在无法更新");
        }
        //3、将DTO转换为实体并设置id
        addressBook = getAddressBookByUpsertReqDTO(addressBookUpsertReqDTO);
        addressBook.setId(id);

        //4、判断是否设置默认地址
        if (addressBook.getIsDefault()==1){
            lambdaUpdate()
                    .eq(AddressBook::getUserId, currentUserId())
                    .eq(AddressBook::getIsDefault, AddressDefaultStatusEnum.DEFAULT.getStatus())
                    .set(AddressBook::getIsDefault, AddressDefaultStatusEnum.NONE_DEFAULT.getStatus())
                    .update();
        }

        //5、修改地址
        baseMapper.updateById(addressBook);


    }

    /**
     * 设置/取消默认地址
     *
     * @param id   地址id
     * @param flag 0取消默认，1设置默认
     * @return
     */
    @Override
    @Transactional
    public void updateDefault(Long id, int flag) {
        //1、根据id获取地址信息
        AddressBook addressBook = baseMapper.selectById(id);
        //2、判断地址是否存在
        if (ObjectUtils.isEmpty(addressBook)) {
            throw new CommonException("地址id不存在无法设置");
        }
        //3、先取消原有的默认地址
        lambdaUpdate()
                .eq(AddressBook::getUserId, currentUserId())
                .eq(AddressBook::getIsDefault, AddressDefaultStatusEnum.DEFAULT.getStatus())
                .set(AddressBook::getIsDefault, AddressDefaultStatusEnum.NONE_DEFAULT.getStatus())
                .update();
        //4、设置新的默认地址
        lambdaUpdate()
                .eq(AddressBook::getId, id)
                .set(AddressBook::getIsDefault, AddressDefaultStatusEnum.DEFAULT.getStatus())
                .update();
    }

    /**
     * 获取当前用户的默认地址
     *
     * @return 默认地址
     */
    @Override
    public AddressBook getDefaultAddress() {
        return lambdaQuery()
                .eq(AddressBook::getUserId, currentUserId())
                .eq(AddressBook::getIsDefault, AddressDefaultStatusEnum.DEFAULT.getStatus())
                .one();
    }

}
